{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面是一个简单的 `asyncio` 示例，演示了如何并发地执行多个异步任务：\n",
    "\n",
    "这个示例中，`fetch_data()` 函数模拟了一个网络请求操作（实际上使用 `asyncio.sleep()` 代替），`main()` 函数则并发地执行了 5 个这样的任务，并等待它们全部完成。最后，`asyncio.run(main())` 启动了事件循环并运行了主协程。\n",
    "但是需要注意的是,下面这个例子实际上过度的依赖了await的功能,也就是说,假设各个任务需要1s,这里就是ns,完全没有时间上的优化."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这个语法非常的类似生成器函数,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "RuntimeError",
     "evalue": "asyncio.run() cannot be called from a running event loop",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
      "\u001b[1;32m/root/MyCode/trashbin/asyncio.ipynb Cell 2\u001b[0m line \u001b[0;36m1\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/asyncio.ipynb#W1sdnNjb2RlLXJlbW90ZQ%3D%3D?line=11'>12</a>\u001b[0m     \u001b[39mprint\u001b[39m(results)\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/asyncio.ipynb#W1sdnNjb2RlLXJlbW90ZQ%3D%3D?line=13'>14</a>\u001b[0m \u001b[39m# 运行主协程\u001b[39;00m\n\u001b[0;32m---> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/asyncio.ipynb#W1sdnNjb2RlLXJlbW90ZQ%3D%3D?line=14'>15</a>\u001b[0m asyncio\u001b[39m.\u001b[39;49mrun(main())\n",
      "File \u001b[0;32m/opt/anaconda3/envs/mathmodal/lib/python3.10/asyncio/runners.py:33\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(main, debug)\u001b[0m\n\u001b[1;32m      9\u001b[0m \u001b[39m\u001b[39m\u001b[39m\"\"\"Execute the coroutine and return the result.\u001b[39;00m\n\u001b[1;32m     10\u001b[0m \n\u001b[1;32m     11\u001b[0m \u001b[39mThis function runs the passed coroutine, taking care of\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m     30\u001b[0m \u001b[39m    asyncio.run(main())\u001b[39;00m\n\u001b[1;32m     31\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m     32\u001b[0m \u001b[39mif\u001b[39;00m events\u001b[39m.\u001b[39m_get_running_loop() \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[0;32m---> 33\u001b[0m     \u001b[39mraise\u001b[39;00m \u001b[39mRuntimeError\u001b[39;00m(\n\u001b[1;32m     34\u001b[0m         \u001b[39m\"\u001b[39m\u001b[39masyncio.run() cannot be called from a running event loop\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[1;32m     36\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m coroutines\u001b[39m.\u001b[39miscoroutine(main):\n\u001b[1;32m     37\u001b[0m     \u001b[39mraise\u001b[39;00m \u001b[39mValueError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39ma coroutine was expected, got \u001b[39m\u001b[39m{!r}\u001b[39;00m\u001b[39m\"\u001b[39m\u001b[39m.\u001b[39mformat(main))\n",
      "\u001b[0;31mRuntimeError\u001b[0m: asyncio.run() cannot be called from a running event loop"
     ]
    }
   ],
   "source": [
    "import asyncio\n",
    "\n",
    "async def process_netdata(delay, data):\n",
    "    # await 本身也会创建一个coroutine对象,这个对象被当作Task加入到Loop中\n",
    "    await asyncio.sleep(delay)\n",
    "    print(data)\n",
    "\n",
    "async def fetch_data(url):\n",
    "    # 模拟网络请求（这里使用 sleep 代替）\n",
    "    await asyncio.sleep(1)\n",
    "    return f\"Data from {url}\"\n",
    "\n",
    "# 这个函数现在返回的是一个coroutine对象 它将会被当作Task加入队列\n",
    "async def main():\n",
    "    # 并发地执行多个异步任务\n",
    "    tasks = [fetch_data(f\"http://example.com/{i}\") for i in range(5)]\n",
    "    results = await asyncio.gather(*tasks)\n",
    "    print(results)\n",
    "\n",
    "# 运行主协程 相当于EventLoop 同时进入非同步模式\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 用另一个含有time的例子解释\n",
    "import asyncio\n",
    "import time\n",
    "\n",
    "async def say_after(delay, what):\n",
    "    await asyncio.sleep(delay)\n",
    "    print(what)\n",
    "\n",
    "async def main():\n",
    "    print(f\"started at {time.strftime('%X')}\")\n",
    "    # 这里实际上做了两件事,1. 创造一个Task 2. 把这个Task加入到Loop中 3. 等待这个Task完成\n",
    "    await say_after(1, 'hello')\n",
    "    await say_after(2, 'world')\n",
    "    print(f\"finished at {time.strftime('%X')}\")\n",
    "\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一个更好的解决方法,真正意义上的使用Loop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import asyncio\n",
    "import time\n",
    "\n",
    "async def say_after(delay, what):\n",
    "    await asyncio.sleep(delay)\n",
    "    print(what)\n",
    "\n",
    "async def main():\n",
    "    # 这个代码相当于显式的分担了await的功能,它单纯的注册一个Task到Loop中,但是还不执行\n",
    "    # 这里不执行的原因是,Python仍然在承担着控制权\n",
    "    task1 = asyncio.create_task(say_after(1, 'hello'))\n",
    "    task2 = asyncio.create_task(say_after(2, 'world'))\n",
    "    print(f\"started at {time.strftime('%X')}\")\n",
    "    # 这里的代码虽然是逻辑上先后的,但是Loop一旦发现两个task可以进行执行,那么它们就会开始处理,而不是等待\n",
    "    await task1\n",
    "    # await的另一个功能是取得coroutine的返回值\n",
    "    await task2\n",
    "    print(f\"finished at {time.strftime('%X')}\")\n",
    "\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取得coroutine的值的写法\n",
    "import asyncio\n",
    "import time\n",
    "\n",
    "async def say_after(delay, what):\n",
    "    await asyncio.sleep(delay)\n",
    "    return f\"{what}-{delay}\"\n",
    "\n",
    "async def main():\n",
    "    task1 = asyncio.create_task(say_after(1, 'hello'))\n",
    "    task2 = asyncio.create_task(say_after(2, 'world'))\n",
    "    print(f\"started at {time.strftime('%X')}\")\n",
    "    # 这里的多个await可以用gather进行优化\n",
    "    ret1 = await task1\n",
    "    ret2 = await task2\n",
    "    print(ret1)\n",
    "    print(ret2)\n",
    "    print(f\"finished at {time.strftime('%X')}\")\n",
    "\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 对多个await的一种优化写法\n",
    "import asyncio\n",
    "import time\n",
    "\n",
    "async def say_after(delay, what):\n",
    "    await asyncio.sleep(delay)\n",
    "    return f\"{what} after {delay} second(s)\"\n",
    "\n",
    "async def main():\n",
    "    task1 = asyncio.create_task(\n",
    "        say_after(1, 'hello')\n",
    "    )\n",
    "    task2 = asyncio.create_task(\n",
    "        say_after(2, 'world')\n",
    "    )\n",
    "\n",
    "    print(f\"started at {time.strftime('%X')}\")\n",
    "\n",
    "    ret = await asyncio.gather(task1, task2)\n",
    "    # 得到的List的结果顺序就是Task的结果顺序\n",
    "    print(ret)\n",
    "\n",
    "    print(f\"finished at {time.strftime('%X')}\")\n",
    "\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这种gather返回的似乎是future对象,不仅如此,在这种写法下甚至不用显式的注册为Task\n",
    "import asyncio\n",
    "import time\n",
    "\n",
    "async def say_after(delay, what):\n",
    "    await asyncio.sleep(delay)\n",
    "    return f\"{what} after {delay} second(s)\"\n",
    "\n",
    "async def main():\n",
    "    # 不需显式的注册为task了\n",
    "    ret = await asyncio.gather(\n",
    "        say_after(1, 'hello'),\n",
    "        say_after(2, 'world')\n",
    "    )\n",
    "    print(ret)\n",
    "\n",
    "    print(f\"finished at {time.strftime('%X')}\")\n",
    "\n",
    "asyncio.run(main())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "某种程度上确实是实现了并发,因为等待的时候还可以做其他的,但是我们没办法控制EventLoop中谁在执行.\n",
    "不仅如此,只有await或者主动归还控制权之后才可以执行其他的.如果代码中没有wait的部分,例如网络,那么这个库实际上是没有帮助的.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mathmodal",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
